#ifndef SMART_POINTER_H
#define SMART_POINTER_H

#include <iostream>
#include <thread>
#include <mutex>

template <typename T>
class SmartPointer
{
public:
    SmartPointer(T *ptr);

    ~SmartPointer();

private:
    T *_ptr;
};

template <typename T>
class AutoPointer
{
public:
    AutoPointer(T *ptr);

    AutoPointer(AutoPointer &ap);

    T &operator*();

    T &operator->();

    AutoPointer &operator=(AutoPointer<T> &ap);

    ~AutoPointer();

private:
    T *_ptr;
};

template <typename T>
class UniquePointer
{
public:
    UniquePointer(T *ptr);
    T &operator->();
    T &operator*();
    ~UniquePointer();
    UniquePointer(UniquePointer &) = delete;
    UniquePointer &operator=(UniquePointer &) = delete;

private:
    T *_ptr;
};

template <typename T>
class SharedPointer
{
public:
    SharedPointer(T *ptr = nullptr);
    T *operator->();
    T &operator*();
    ~SharedPointer();
    SharedPointer(SharedPointer<T> &);
    SharedPointer<T> &operator=(SharedPointer<T> &);
    void Release();
    void AddRef();
    int use_count() const;
    T* get() const;
    void SubRef();

private:
    T *_ptr = nullptr;
    int *_pCount = nullptr;
    std::mutex *_pMutex;
};

class Student
{
public:
    Student(std::string name, int age, std::string sex);
    ~Student();

private:
    std::string _name;
    int _age;
    std::string _sex;
};

template <typename T>
class WeakPointer
{
public:
    WeakPointer(T* ptr = nullptr);
    WeakPointer(const SharedPointer<T>& sp);
    WeakPointer<T>& operator=(const WeakPointer<T>& wp);
    T* operator->();
    T& operator*();

private:
    T* _ptr;
};

class ListNode
{
public:
    // ListNode *_prev = nullptr;
    // ListNode *_next = nullptr;
    // SharedPointer<ListNode> _prev;
    // SharedPointer<ListNode> _next;
    WeakPointer<ListNode> _prev;
    WeakPointer<ListNode> _next;
    int _val = 0;
};
#endif